package com.cinyi.ormx.android.model;

import java.lang.reflect.Field;
import java.sql.Date;
import java.sql.Timestamp;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.cinyi.ormlite.annotation.AnnotationNotFoundException;
import com.cinyi.ormlite.annotation.TConstrains;
import com.cinyi.ormlite.annotation.TField;
import com.cinyi.ormlite.annotation.TSchema;
import com.cinyi.ormlite.annotation.TTable;
import com.cinyi.ormlite.core.BaseModel;
import com.cinyi.ormlite.core.IGenericDao;
import com.cinyi.ormx.android.context.LogHelper;
import com.cinyi.ormx.android.dao.AndroidGenericDaoImpl;

@SuppressWarnings("rawtypes")
public class AndroidBaseModel<T extends BaseModel> extends BaseModel<T>{
	/**
	 * 
	 */
	private static final long serialVersionUID = -7099565195903593700L;
	public static final String DEFAULT_SCHEMA = "default";
	
	/**
	 * 数据库名
	 */
	private String schema = null ;
	
	private String createSqlScript = null ;
	
	private IGenericDao<T> dao = null ;
	
	private Context context ;
	public AndroidBaseModel(Context context){
		this.context = context ;
	}
	
	@Override
	public String getId() {
		return null;
	}

	public String getSchema()
    {
        if(schema == null ){
            schema = DEFAULT_SCHEMA  ;
            if(this.getClass().isAnnotationPresent(TSchema.class)){
                TSchema schm = getClass().getAnnotation(TSchema.class);
                if(schm.alia() != null)
                    schema = schm.alia() ;
            }
        }
        return schema;
    }
    
	public void CreateIfNoExists(SQLiteDatabase sqlitedatabase) {
		StringBuilder stringbuilder = new StringBuilder(
				"SELECT COUNT(*) FROM sqlite_master where type='table' and name='");
		stringbuilder.append(getSchema()).append("'").toString();

		Cursor cursor = sqlitedatabase.rawQuery(stringbuilder.toString(), null);
		try{
			cursor.moveToFirst();
			if (cursor.isAfterLast() || cursor.getInt(0) == 0) { 
				String cSQL = createTable() ;
				LogHelper.d("db","cerate SQL: " + cSQL );
				sqlitedatabase.execSQL(cSQL);
			}
		}catch(Exception se){
			se.printStackTrace();
		}finally{
			cursor.close();
		}
	}

	private String createTable() throws Exception {
		if(createSqlScript == null){
			Class<?> clazz = getClass();
		        if(!clazz.isAnnotationPresent(TTable.class)){
		            throw new NullPointerException("the table not found:" + clazz.getSimpleName());
		        }
		        String tableName = getTableName(clazz);
		        //存储所有字段的信息
		        //通过反射获得要查询的字段
		        StringBuffer createCommond = new StringBuffer();
		        Field[] fields = clazz.getDeclaredFields();
		        for (Field field : fields) {
		            if (field.isAnnotationPresent(TField.class)) {
		                TField tfield = field.getAnnotation(TField.class);
		                String idFieldName = tfield.name();
		                createCommond.append(" `").append(idFieldName).append("` ");
		                Class<?> clazzField = tfield.type() ;
		                if(clazzField == String.class && tfield.length() == 0){
		                    throw new NullPointerException("varcahr's lenght required:" + idFieldName );
		                }

		                String paramVal = "" ;
		                if (clazzField == String.class) {
		                    paramVal = " varchar " ;
		                } else if (clazzField == short.class || clazzField == Short.class||clazzField == int.class || clazzField == Integer.class || clazzField == long.class || clazzField == Long.class || clazzField == byte.class || clazzField == Byte.class ) {
		                    paramVal = " int " ;
		                } else if (clazzField == Date.class) {
		                    paramVal = "date" ;
		                } else if (clazzField == Timestamp.class) {
		                    paramVal = "timestamp" ;
		                } else {
		                    createCommond.append(" ").append(tfield.type().getSimpleName().toLowerCase());
		                } 
		                createCommond.append(paramVal) ;

		                if(tfield.length()>0){
		                    createCommond.append("(").append(tfield.length()).append(") ") ;
		                }
		                
		                TConstrains tc = tfield.constrains();
		                createCommond.append(getConstrains(tc));
		                createCommond.append("\n,");
		            }
		        }
		        createCommond.deleteCharAt(createCommond.length()-1);
		        
		        createSqlScript = "CREATE TABLE IF NOT EXISTS `"+ tableName +"` ( \n";  
		        createSqlScript += createCommond.toString() +" \n ) ";  
		}
		
		
		return createSqlScript ;
	}

	public boolean dropTableIfExists(SQLiteDatabase sqlitedatabase) {
		String sSQL = " DROP TABLE IF EXISTS " + getSchema() ;
		sqlitedatabase.execSQL(sSQL);
		return true ;
	}
	
	public String getCreateSqlScript() {
		return createSqlScript;
	}
	
	private String getTableName(Class<?> clazz) throws AnnotationNotFoundException {
        if (clazz.isAnnotationPresent(TTable.class)) {
            TTable entity = clazz.getAnnotation(TTable.class);
            return entity.value();
        } else {
            throw new AnnotationNotFoundException(clazz.getName() + " is not Table Annotation.");
        }
    }
    
     private static String getConstrains(TConstrains constrain) {  
        String rst = "";  
        if(constrain.notNull()){  
            rst += " not null ";  
        }  
        if(constrain.primaryKey()){  
            rst += " primary key ".toLowerCase();  
        }  
        if(constrain.unique()){  
            rst += " unique ".toLowerCase();  
        } 
        
        if(constrain.auto()){  
            rst += " AUTO_INCREMENT ".toLowerCase();  
        } 
        return rst;  
    } 
     
     @Override
     public IGenericDao<T> getDao()
     {
         if(dao == null){
         	dao = new AndroidGenericDaoImpl<T>(context);
         }
         return dao;
     }
     
}
